package avicit.bdp.dcs.datasource.service;

import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.common.utils.enums.JobType;
import avicit.bdp.dcs.datasource.dto.JobDatasource;
import avicit.bdp.dcs.job.dto.JobDTO;
import avicit.bdp.dcs.job.service.DcsJobService;
import avicit.bdp.dcs.task.dto.TaskDTO;
import avicit.bdp.dcs.task.service.TaskService;
import avicit.bdp.dcs.tools.enums.Enable;
import avicit.bdp.dcs.utils.DcsConstants;
import avicit.bdp.dcs.utils.DcsErrorCode;
import avicit.bdp.dcs.utils.JdbcConstants;
import avicit.platform6.core.exception.BusinessException;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author liyb
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class TableService {

    private static final Logger logger = LoggerFactory.getLogger(TableService.class);

    private static final String COLUMN_NAME_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,49}$";

    @Autowired
    private DcsJobService jobService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private BaseDbService baseDbService;
    @Autowired
    private DataSourceUtils dataSourceUtils;

    /**
     * 相同表名检测
     *
     * @param jobId jobId
     * @return 相同表名检测结果
     */
    public boolean sameTableNameTest(String jobId) throws Exception {
        boolean flag = false;
        JobDTO jobDTO = jobService.selectByPrimaryKey(jobId);
        CheckParaUtils.checkDbObjectValidity(jobDTO, logger, String.format(DcsErrorCode.JOB_NULL.getDesc(), jobId));

        // 根据数据源id获取所有表名
        List<String> tableList = baseDbService.getTableList(jobDTO.getDstDatasourceId());

        TaskDTO taskDTO = new TaskDTO();
        taskDTO.setJobId(jobId);
        taskDTO.setFlag(Enable.ZERO.getCode());
        List<TaskDTO> taskList = taskService.selectList(taskDTO);
        if (CollectionUtils.isNotEmpty(taskList)) {
            for (TaskDTO task : taskList) {
                if(CollectionUtils.isNotEmpty(tableList)) {
                    if(tableList.contains(task.getDstTableName()) || tableList.contains(task.getDstTableName().toLowerCase())
                            || tableList.contains(task.getDstTableName().toUpperCase())){
                        flag = true;
                        logger.info("jobId:{}目标库中包含相同表:{}", jobId, task.getDstTableName());
                        break;
                    }
                }
            }
        }
        return flag;
    }

    /**
     * 校验表名称
     *
     * @param jobId jobId
     * @return 校验表名称结果
     */
    public boolean isValidTableName(String jobId) {
       try {
           checkTableName(jobId);
           return true;
       }catch (Exception e){
           e.printStackTrace();
           return false;
       }
    }

    /**
     * 校验表名称
     *
     * @param jobId jobId
     * @return 校验表名称结果
     */
    public void checkTableName(String jobId) throws Exception {
        JobDTO job = jobService.selectByPrimaryKey(jobId);
        String tableNamePattern = baseDbService.getTableNamePattern(job.getDstDatasourceId());
        String tableNamePatternTips = baseDbService.getTableNamePatternTips(job.getDstDatasourceId());
        JobDatasource dstDatasource = dataSourceUtils.convertDatasource(job.getDstDatasourceId());

        TaskDTO taskDTO = new TaskDTO();
        taskDTO.setJobId(jobId);
        taskDTO.setFlag(Enable.ZERO.getCode());
        List<TaskDTO> taskList = taskService.selectList(taskDTO);
        if (CollectionUtils.isNotEmpty(taskList)) {
            for (TaskDTO task : taskList) {
                if(task.getJobType() == JobType.STREAM.getCode()){
                    String[] arr = task.getDstTableName().split(",");
                    for(String tableName : arr){
                        if (JdbcConstants.IOTDB.equals(dstDatasource.getDbType())) {
                            iotdbCheck(tableName);
                        }else{
                            matcher(tableName, tableNamePattern, tableNamePatternTips);
                        }
                    }
                }else{
                    if (JdbcConstants.IOTDB.equals(dstDatasource.getDbType())) {
                        iotdbCheck(task.getDstTableName());
                    }else{
                        matcher(task.getDstTableName(), tableNamePattern, tableNamePatternTips);
                    }
                }
            }
        }
    }

    /**
     * 通用正则校验
     * @param tableName
     * @param tableNamePattern
     */
    private void matcher(String tableName, String tableNamePattern, String tableNamePatternTips) {
        Pattern pattern = Pattern.compile(tableNamePattern);
        Matcher matcher = pattern.matcher(tableName);
        if (!matcher.matches()) {
            logger.info("表名称校验不通过，表名为：{}，规则为：{}", tableName, tableNamePattern);
            throw new BusinessException("表名称["+tableName+"]不合法，" + tableNamePatternTips);
        }
    }

    /**
     * 验证时间序列合法性
     */
    private void iotdbCheck(String tableName) {
        if (tableName.split(DcsConstants.SPOT).length < 3) {
            throw new BusinessException(
                    String.format("%s时间序列定义不合法，必须为三级，例：root.xxx.xxx", tableName));
        }
    }

    /**
     * 判断列名是否合法
     *
     * @param columnName 列名
     * @return 列名是否合法
     */
    public boolean isValidColumnName(String columnName) {
        Pattern pattern = Pattern.compile(COLUMN_NAME_PATTERN);
        Matcher matcher = pattern.matcher(columnName);
        return matcher.matches();
    }

}
